package com.xky.redis_cluster.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.retry.policy.TimeoutRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author keying.xia
 */
@Configuration
@ConditionalOnClass(JedisCluster.class)
@EnableConfigurationProperties(JedisClusterProperties.class)
public class JedisClusterConfig {

    @Autowired
    private JedisClusterProperties jedisClusterProperties;

    @Bean
    public JedisCluster jedisClusterFactory(){
        String[] nodeArray =  jedisClusterProperties.getNodes().split(",");
        Set<HostAndPort> nodes = new HashSet<>();
        for (String ipPort:nodeArray){
            String[] ipPortPair = ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));
        }
        return new JedisCluster(nodes,jedisClusterProperties.getConnectionTimeOut(),jedisClusterProperties.getSoTimeOut(),jedisClusterProperties
                .getMaxAttempt(),jedisClusterProperties.getPassword(),jedisPoolConfig());
    }

    @Bean
    public RedisTemplate redisTemplateFactory(){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        return redisTemplate;
    }


    /**
     * RedisCluster配置
     * @return
     */

    @Bean
    public RedisClusterConfiguration redisClusterConfiguration(){
        Map<String, Object> source = new HashMap<String, Object>();
        source.put("spring.redis.cluster.nodes", jedisClusterProperties.getNodes());
        source.put("spring.redis.cluster.timeout", jedisClusterProperties.getConnectionTimeOut());
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
        return redisClusterConfiguration;
    }


    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration(),jedisPoolConfig());
        jedisConnectionFactory.setPassword(jedisClusterProperties.getPassword());
        return  jedisConnectionFactory;
    }


    /**
     * 生成 RetryTemplate 用于代替xml 里的<bean></bean> 属性
     * @return
     */
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
        policy.setTimeout(50);
        retryTemplate.setRetryPolicy(policy);
        return retryTemplate;
    }

    /**
     * jedis 连接池
     * @return
     */
    private JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(jedisClusterProperties.getMaxIdel());
        jedisPoolConfig.setMaxWaitMillis(jedisClusterProperties.getMaxWaitMills());
        jedisPoolConfig.setMinIdle(jedisClusterProperties.getMinIdle());
        jedisPoolConfig.setTestOnBorrow(jedisClusterProperties.isTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(jedisClusterProperties.isTestOnReturn());
        return jedisPoolConfig;
    }


}
